package organizer;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

/**
 * File source that lists all the files of directories recursively.
 * @author dawong
 */
public class RecursiveFileLister implements IFileSource {
    
    private List<File> dirList;
    private Stack<Iterator<File>> iterStack = new Stack();

    public RecursiveFileLister(List<File> dirList) {
        this.dirList = dirList;
        if (dirList != null) {
            iterStack.push(dirList.iterator());
        }
    }

    public File nextFile() {
        if (iterStack.size() > 0) {
            Iterator<File> iter = iterStack.peek();
            return findNext(iter);
        }
        return null;
    }
    
    private File findNext(Iterator<File> iter) {
        if (iter.hasNext()) {
            File file = iter.next();
            // recurse into subdirs
            while (file != null && file.isDirectory()) {
                iter = new DirIterator(file);
                iterStack.push(iter);
                return findNext(iter);
            }
            return file;
        } else {
            iterStack.pop();
            while (iterStack.size() > 0) {
                iter = iterStack.peek();
                return findNext(iter);
            }
        }
        return null;
    }
    
    private static class DirIterator implements Iterator<File> {
        
        private File dir;
        private List<File> fileList;
        private Iterator<File> iter = null;

        public DirIterator(File dir) {
            this.dir = dir;
            fileList = new ArrayList<File>();
            for (File f : dir.listFiles()) {
                fileList.add(f);
            }
            Collections.sort(fileList);
            iter = fileList.iterator();
        }

        public boolean hasNext() {
            return iter.hasNext();
        }

        public File next() {
            return iter.next();
        }

        public void remove() {
            iter.remove();
        }
        
    }

}
